﻿/**
 * describe:General tools
 * date:2022-09-06
 * author:lenny
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Jt808DataParser.Utils
{
    public class CommonUtil
    {
        /// <summary>
        /// Hex format string to byte array
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        public static byte[] HexStringToBytes(string hexString)
        {
            try
            {
                hexString = Regex.Replace(hexString, @".{2}", "$0 ");
                //Split the string with ' ' and remove empty characters
                string[] chars = hexString.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                byte[] returnBytes = new byte[chars.Length];
                //Character by character becomes hexadecimal byte data
                for (int i = 0; i < chars.Length; i++)
                {
                    returnBytes[i] = Convert.ToByte(chars[i], 16);
                }
                return returnBytes;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// Merge byte arrays
        /// </summary>
        /// <param name="bytes1"></param>
        /// <param name="bytes2"></param>
        /// <returns></returns>
        public static byte[] CombineBytes(byte[] bytes1, byte[] bytes2)
        {
            List<byte> tmp = new List<byte>(bytes1.Length + bytes2.Length);
            tmp.AddRange(bytes1);
            tmp.AddRange(bytes2);
            byte[] merged = tmp.ToArray();
            return merged;
        }

        /// <summary>
        /// Report the specified System Byte [] is the index of the first match in this instance.
        /// </summary>
        /// <param name="srcBytes">System. Byte [] where the lookup was performed.</param>
        /// <param name="searchBytes">System. Byte [] to find.</param>
        /// <returns>If the byte array is found, it is the index position of searchbytes;- 1 if the byte array is not found;If searchBytes is null or the length is 0, the return value is - 1.</returns>
        public static int BytesIndexOf(byte[] srcBytes, byte searchBytes)
        {
            if (srcBytes == null) { return -1; }
            if (srcBytes.Length == 0) { return -1; }
            for (int i = 0; i < srcBytes.Length; i++)
            {
                if (srcBytes[i] == searchBytes)
                {
                    return i;
                }
            }
            return -1;
        }

        /// <summary>
        /// Convert hexadecimal string to ASCII string
        /// </summary>
        /// <param name="Data"></param>
        /// <param name="istrans"></param>
        /// <returns></returns>
        public static string HexStrToAsciiString(string Data, bool istrans)
        {
            if (istrans)
            {
                Data = Regex.Replace(Data, @"(?is)(?<=^([0-9a-f]{2})+)(?!$)", " ");
                Data = Data.Replace("3D 00", "3D ").Replace("3D 11", "2C ").Replace("3D 14", "28 ").Replace("3D 15", "29 ").Replace(" ", "");
            }
            int count = Data.Length / 2;
            string strContent = "";
            char[] num = new char[count];
            for (int i = 0; i < count; i++)
            {
                string str = Data.Substring(i * 2, 2);
                byte by = Convert.ToByte(Convert.ToInt32(str, 16));
                num[i] = Convert.ToChar(by);
                strContent += num[i].ToString();
            }
            return strContent;
        }

        /// <summary>
        /// Binary to ASCII
        /// </summary>
        /// <param name="bt"></param>
        /// <returns></returns>
        public static string ByteToASCII(byte[] bt)
        {
            string lin = "";
            for (int i = 0; i < bt.Length; i++)
            {
                lin = lin + bt[i] + " ";
            }
            string[] ss = lin.Trim().Split(new char[] { ' ' });
            char[] c = new char[ss.Length];
            int a;
            for (int i = 0; i < c.Length; i++)
            {
                a = Convert.ToInt32(ss[i]);
                c[i] = Convert.ToChar(a);
            }

            string b = new string(c);
            return b.Replace("\u0000", "");
        }

        /// <summary>
        /// Time format conversion
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static DateTime GetDataTime(byte[] bytes)
        {
            string hexTime = ByteToHexStr(bytes);
            if (hexTime.Equals("000000000000"))
            {
                hexTime = "000101000000";
            }
            return DateTime.ParseExact(hexTime, "yyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Time format conversion
        /// </summary>
        /// <param name="strdate"></param>
        /// <returns></returns>
        public static DateTime GetDataTime(string strdate)
        {
            return DateTime.ParseExact(strdate, "yyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Get the value of the binary index bit
        /// </summary>
        /// <param name="number"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static int getBitValue(long number, int index)
        {
            return (number & (1 << index)) > 0 ? 1 : 0;
        }

        /// <summary>
        /// Convert byte array to hex string
        /// </summary>
        /// <param name="byteDatas"></param>
        /// <returns></returns>
        public static string ByteToHexStr(byte[] byteDatas)
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < byteDatas.Length; i++)
            {
                builder.Append(string.Format("{0:X2}", byteDatas[i]));
            }
            return builder.ToString().Trim();
        }

        /// <summary>
        /// Convert hexadecimal value to unsigned int value(2 bytes)
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static ushort SwapUInt16(ushort v)
        {
            return (ushort)(((v & 0xff) << 8) | ((v >> 8) & 0xff));
        }

        /// <summary>
        /// Convert hexadecimal value to unsigned int value(4 bytes)
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static uint SwapUInt32(uint v)
        {
            return (uint)(((SwapUInt16((ushort)v) & 0xffff) << 0x10) |
                           (SwapUInt16((ushort)(v >> 0x10)) & 0xffff));
        }

        /// <summary>
        /// Short to Bytes
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static byte[] ShortToBytes(short number)
        {
            byte byte2 = (byte)(number >> 8);
            byte byte1 = (byte)(number & 255);
            byte[] bytes = new byte[2];
            bytes[0] = byte1;
            bytes[1] = byte2;
            return bytes.Reverse().ToArray();
        }

        /// <summary>
        /// Random
        /// </summary>
        /// <returns></returns>
        public static short RandomNumber(int min, int max)
        {
            Random rd = new Random();
            return (short)rd.Next(min, max);
        }

        /// <summary>
        /// Calculate check code
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static byte xor(List<byte> bytes)
        {
            int checksum = 0;
            foreach (byte b in bytes)
            {
                checksum ^= b;
            }
            return (byte)(checksum & 0xff);
        }

        /// <summary>
        /// Escape
        /// </summary>
        /// <param name="inBytes"></param>
        /// <returns></returns>
        public static byte[] escape(List<byte> inBytes)
        {
            List<byte> outBytes = new List<byte>();
            foreach (byte b in inBytes)
            {
                if (b == 0x7E)
                {
                    outBytes.AddRange(HexStringToBytes("7D02"));
                }
                else if (b == 0x7D)
                {
                    outBytes.AddRange(HexStringToBytes("7D01"));
                }
                else
                {
                    outBytes.Add(b);
                }
            }
            return outBytes.ToArray();
        }

        /// <summary>
        /// Unescape
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="bodyLen"></param>
        /// <returns></returns>
        public static List<byte> unescape(byte[] bytes, int bodyLen)
        {
            int i = 0;
            List<byte> frame = new List<byte>();
            while (i < bodyLen)
            {
                byte b = bytes[i];
                if (b == 0x7D)
                {
                    byte nextByte = bytes[i + 1];
                    if (nextByte == 0x01)
                    {
                        frame.Add(0x7D);
                    }
                    else if (nextByte == 0x02)
                    {
                        frame.Add(0x7E);
                    }
                    else
                    {
                        //Abnormal data
                        frame.Add(b);
                        frame.Add(nextByte);
                    }
                    i += 2;
                }
                else
                {
                    frame.Add(b);
                    i++;
                }
            }
            return frame;
        }

        /// <summary>
        /// Unified processing message ID(short)
        /// </summary>
        /// <param name="msgId"></param>
        /// <returns></returns>
        public static string formatMessageId(int msgId)
        {
            return string.Format("0x{0}", msgId.ToString("X").PadLeft(4,'0'));
        }

        /// <summary>
        /// Unified processing message ID(long)
        /// </summary>
        /// <param name="msgId"></param>
        /// <returns></returns>
        public static string formatLongToHex(long msgId)
        {
            return string.Format("0x{0}", msgId.ToString("X").PadLeft(8, '0'));
        }
    }
}
